package com.rupeng.hibernate.cfg;

import java.io.File;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

public class Configuration {

	//the configuration of Hibernate
	private static Properties cfgProperties;
	
	public static final String SESSION_FACTORY_NAME = "hibernate.session_factory_name";
	
	//grobal configure file hibernate.cfg.xml
	private final static String GROBAL_CONFIG_FILE_NAME;
	
	static {
		GROBAL_CONFIG_FILE_NAME = "hibernate.cfg.xml";
		cfgProperties = new Properties();
	}
	
	public Configuration configure() {
		return this.configure(GROBAL_CONFIG_FILE_NAME);
	}
	
	private Configuration configure(String resource) {		
		InputStream stream = ConfigHelper.parsePOMapping(resource);
		return this.doConfigure(stream);
	}
	
	private Configuration doConfigure(InputStream stream) {
		org.dom4j.Document doc = ConfigHelper.parsePOMapping(stream);
		return this.doConfigure(doc);
	}
	
	private Configuration doConfigure(org.dom4j.Document doc) {
		Element sfNode = doc.getRootElement().element("session-factory");
		String name = sfNode.attributeValue("name");
		if (name != null) {
			cfgProperties.setProperty(SESSION_FACTORY_NAME, name);
		}
		
		addProperties(sfNode);
		parseMapping(sfNode);
		
		return this;
	}
	
	/**
	 * add all "property" to properties
	 * @param parent the parent Element of property
	 */
	private void addProperties(Element parent) {
		Iterator iter = parent.elementIterator("property");
		
		while (iter.hasNext()) {
			Element node = (Element) iter.next();
			String name = node.attributeValue("name");
			String value = node.getText().trim();

			cfgProperties.setProperty(name, value);
//System.out.println( name + " | " + value );
			if (!name.startsWith("hibernate")) {
				cfgProperties.setProperty("hibernate." + name, value);
			}
		}
	}
	
	/**
	 * parse the configuration of PO
	 * @param parent the parent Element of property
	 */
	private void parseMapping(Element parent) {
		Iterator iter = parent.elementIterator("mapping");
		
		if(iter != null) {
			this.cfgProperties.setProperty("mapping", "true");
		}
		
		int i = 1;
		while (iter.hasNext()) {
			Element node = (Element) iter.next();
			String name = node.attributeValue("resource");
			String value = nameToPath(name);
			name = pathToObjName(value);
			
			cfgProperties.setProperty(name, value);
//System.out.println(name + " | " + value);			
		}
	}
	
	public static void readPOMapping(String resource, Properties properties) {
		InputStream stream = ConfigHelper.parsePOMapping(resource);
		org.dom4j.Document doc = ConfigHelper.parsePOMapping(stream);
		ConfigHelper.parsePOMapping(doc, properties);
	}
	
	/**
	 * change package name to path
	 * @param str package name
	 * @return path
	 */
	private static String nameToPath(String str) {
		String value = str;
		
		String[] v = value.split("/");
		value = v[0].replace(".", "/");
		value = value + "/" + v[1];
		
		return value;
	}
	
	/**
	 * change path to Object name
	 * @param str path
	 * @return Object name
	 */
	private static String pathToObjName(String str) {
		String objName = str;
		
		objName = objName.substring(0, objName.length() - 8);
		objName = objName.replace("/", ".");
//System.out.println("objName:" + objName);
		
		return objName;
	}

	public Properties getCfgProperties() {
		return cfgProperties;
	}

	public void setCfgProperties(Properties cfgProperties) {
		this.cfgProperties = cfgProperties;
	}
}
